package club.kynb.mall.application.interceptor;

import club.kynb.mall.application.config.AuthProperties;
import club.kynb.mall.application.constant.AuthConst;
import club.kynb.mall.application.constant.MallResultCode;
import club.kynb.mall.application.context.MallUserContext;
import club.kynb.mall.application.repository.AuthRepository;
import club.kynb.mall.basic.constant.HeaderConst;
import club.kynb.mall.basic.dto.HeaderDTO;
import cn.hutool.core.util.StrUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.pizza.common.web.exception.Errors;
import org.pizza.common.web.mvc.util.WebUtil;
import org.pizza.util.Checker;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

/**
 * @author kynb_club@163.com
 * @since 2021/6/24 9:58 上午
 */
@Slf4j
@Component
@AllArgsConstructor
public class AuthenticationInterceptor implements HandlerInterceptor, EnvironmentAware {
    private final AuthRepository authRepository;
    private final AuthProperties authProperties;
    private Environment env;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        MallUserContext.build(assembleHead(request));
        if (hasUrl(request, authProperties.getIgnoreUrs())) {
            return true;
        }
        final boolean isSpecialUrl = hasUrl(request, authProperties.getSpecialUrs());
        String token = request.getHeader(HeaderConst.TOKEN);
        Checker.ifThrow(StrUtil.isBlank(token) && !isSpecialUrl, () -> Errors.BIZ.exception(MallResultCode.CODE_11009));
        final Optional<MallUserContext> contextOptional = authRepository.getContext(String.format("%s:%s", AuthConst.TOKEN_PREFIX, token));
        MallUserContext mallUserContext;
        if (isSpecialUrl) {
            contextOptional.ifPresent(MallUserContext::build);
        } else {
            mallUserContext = contextOptional.orElseThrow(() -> Errors.BIZ.exception(MallResultCode.CODE_11010));
            MallUserContext.build(mallUserContext);
        }
        return true;
    }

    private HeaderDTO assembleHead(HttpServletRequest request){
        String deviceType = request.getHeader(HeaderConst.DEVICE_TYPE);
        String clientIp = WebUtil.getIP(request);
        String deviceId = request.getHeader(HeaderConst.DEVICE_ID);
        String latitude = request.getHeader(HeaderConst.LATITUDE);
        String longitude = request.getHeader(HeaderConst.LONGITUDE);
        String apiVersion = request.getHeader(HeaderConst.API_VERSION);
        String appVersion = request.getHeader(HeaderConst.APP_VERSION);
        String clientType = request.getHeader(HeaderConst.CLIENT_TYPE);
        HeaderDTO headerDTO = new HeaderDTO();
        headerDTO.setClientIp(clientIp);
        headerDTO.setLongitude(longitude);
        headerDTO.setLatitude(latitude);
        headerDTO.setDeviceId(deviceId);
        headerDTO.setDeviceType(deviceType);
        headerDTO.setAppVersion(appVersion);
        headerDTO.setApiVersion(apiVersion);
        headerDTO.setClientType(clientType);
        return headerDTO;
    }


    private boolean hasUrl(HttpServletRequest request, List<String> urls) {
        String requestURI = request.getRequestURI();
        if (Objects.nonNull(env)) {
            final String contextPath = env.getProperty("server.servlet.context-path");
            if (StrUtil.isNotBlank(contextPath)) {
                requestURI = requestURI.replace(contextPath, "");
            } else {
                log.error("Environment 注入失败了~");
            }
        }
        boolean skip = false;
        for (String s : urls) {
            if (s.contains("*")) {
                s = s.replace("/*", "");
                if (requestURI.startsWith(s)) {
                    skip = true;
                    break;
                }
            }
            if (s.equals(requestURI)) {
                skip = true;
                break;
            }
        }
        return skip;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        MallUserContext.clear();
    }

    @Override
    public void setEnvironment(Environment environment) {
        this.env = environment;
    }
}
